/********************************************************************************
 * Project Name		[JavaSE_Fundamentals]
 * File Name     	[TestProducerConsumer2.java]
 * Creation Date 	[2015-01-01]
 * 
 * Copyright© ge.y.yang@gmail.com All Rights Reserved
 * 
 * Work hard, play harder, think big and keep fit
 ********************************************************************************/
package thread.producerConsumer;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 生产者消费者模式 2 - 使用Lock的await()/signalAll()
 * 
 * @author 不落的太阳(Sean Yang aka ShortPeace)
 * @version 1.0
 * @since jdk 1.8
 * 
 */
public class TestProducerConsumer2 implements Warehouse {

	// 仓库最大的存储量
	private static final int MAX_SIZE = 100;

	// 仓库的载体
	private LinkedList<String> list = new LinkedList<String>();

	// 锁
	private final Lock lock = new ReentrantLock();

	// 仓库满的条件
	private final Condition full = lock.newCondition();

	// 仓库空的条件
	private final Condition empty = lock.newCondition();

	/**
	 * 生产方法
	 * 
	 * @throws InterruptedException
	 */
	@Override
	public void produce(int number) throws InterruptedException {
		lock.lock();
		// 如果仓库容量不足
		while (list.size() + number > MAX_SIZE) {
			System.out.println("[要生产的产品数量]: " + number + "\t[库存量]: " + list.size() + "\t暂时不能执行生产任务.");
			// 不能满足生产, 产生阻塞
			full.await();
		}

		// 生产条件满足, 生产number个产品
		for (int i = 1; i <= number; i++) {
			list.add(new String("产品" + i));
		}
		System.out.println("[已经生产的产品数量]: " + number + "\t[库存量]: " + list.size());

		// 唤醒其他所有线程
		full.signalAll();
		empty.signalAll();

		lock.unlock();
	}

	/**
	 * 消费方法
	 * 
	 * @return
	 * @throws InterruptedException
	 */
	@Override
	public synchronized void consume(int number) throws InterruptedException {
		lock.lock();
		// 库存不足, 不能消费
		while (list.size() < number) {
			System.out.println("[要消费的产品数量]: " + number + "\t[库存量]: " + list.size() + "\t暂时不能执行消费任务.");
			// 不能满足消费, 产生阻塞
			empty.await();
		}

		// 消费满足的情况下, 消费number个产品
		for (int i = 1; i <= number; i++) {
			list.remove();
		}
		System.out.println("[已消费的产品数量]: " + number + "\t[库存量]: " + list.size());

		// 唤醒其他所有线程
		full.signalAll();
		empty.signalAll();

		lock.unlock();
	}

	public static void main(String[] args) {
		Warehouse warehouse = new TestProducerConsumer2();

		Producer p1 = new Producer(warehouse, 10);
		Producer p2 = new Producer(warehouse, 30);
		Producer p3 = new Producer(warehouse, 20);
		Producer p4 = new Producer(warehouse, 50);
		Producer p5 = new Producer(warehouse, 40);

		Consumer c1 = new Consumer(warehouse, 50);
		Consumer c2 = new Consumer(warehouse, 20);
		Consumer c3 = new Consumer(warehouse, 70);

		c1.start();
		c2.start();
		c3.start();
		p1.start();
		p2.start();
		p3.start();
		p4.start();
		p5.start();
	}
}
